useReducer和useState都是用於資料狀態管理的Hook,
那我該怎麼區分使用他們的時機呢?
useState
:
適合用於不受其他state影響的獨立資料狀態。
useReducer
:
適合用於受其他較多條件影響、複雜的資料狀態。
我們多將 useReducer
和 context API
用來做全域共用state的管理,
透過ruducer函式裡的判斷條件來更新state,更方便集中管理邏輯複雜的state。
//App.js
import React, { useReducer } from 'react';
//我設資料初始值為物件,裡面帶兩個之後要使用的值
const setValue = {
text: "黑色", color: 'black'
}
reducer
自定義判斷資料更新的ruducer函式,有兩個參數state、action可以使用,根據action條件的不同,決定返回的新state資料。
//自定義的reducer函式
function reducer(state, action) {
//判斷action等於dispatch帶入的參數,我取裡面的type值做更新判斷
switch (action.type) {
case 'red':
return {
text: '紅色', color: action.type
}
case 'blue':
return {
text: '藍色', color: action.type
}
default:
return state;
}
}
其中兩個傳入的參數為
reducer:
第三步建立的reducer
函式,讓useReducer可以根據它返回正確要更新的資料。
setValue:
第一步設立的初始資料格式。
//const [state, dispatch] = useReducer(reducer函式, 初始資料);
//照前面步驟的設定放入參數
const [state, dispatch] = useReducer(reducer, setValue);
而我們宣告的變數(可自訂)分別是:
state:
這裡的state可以在jsx上用props傳入子元件,或是搭配上上篇的context設定全域state。
dispatch:
接收action參數的函式,我們會根據傳入的action,帶入第三步的ruducer做判斷返回更新state給useReducer的state
這樣點擊更新資料後,我們就可以利用useReducer保存的state了,
在這邊我們將state傳入context做全域資料,讓下兩層的子元件使用。
function App() {
//
const [state, dispatch] = useReducer(reducer, setValue);
return (
<div className="App">
//點擊按鈕後使用dispatch傳入action到ruducer函式做條件判斷(action的值也可以用物件傳入)
<button onClick={() => dispatch({ type: 'red' })}>切到紅色</button>
<button onClick={() => dispatch({ type: 'blue' })}>切到藍色</button>
//將useReducer的state資料傳入context
<ContextState.Provider value={state}>
<Child />
</ContextState.Provider>
</div >)
}
最後呈現的效果如下:
全部的程式碼:
App.js
import React, { useReducer } from 'react';
import './App.css';
import { ContextState } from './context/ContextState.js'
import Child from './component/Child';
const setValue = {
text: "黑色", color: 'black'
}
function reducer(state, action) {
switch (action.type) {
case 'red':
return {
text: '紅色', color: action.type
}
case 'blue':
return {
text: '藍色', color: action.type
}
default:
return state;
}
}
//元件function
function App() {
const [state, dispatch] = useReducer(reducer, setValue);
return (
<div className="App">
<button onClick={() => dispatch({ type: 'red' })}>切到紅色</button>
<button onClick={() => dispatch({ type: 'blue' })}>切到藍色</button>
//context
<ContextState.Provider value={state}>
<Child />
</ContextState.Provider>
</div >)
}
export default App;
Child.js
import React from 'react';
import './Child.css'
import Grandson from './Grandson'
function Child() {
return (
<div className="App child-wrap" >
<h4>Child元件用不到context</h4>
<Grandson />
</div>)
}
export default Child;
Grandson.js
import React, { useContext } from 'react';
import { ContextState } from '../context/ContextState'
function Grandson() {
const getContext = useContext(ContextState)
const styleColor = { color: getContext.color }
return (
<div className="App grandson-wrap" >
Grandson元件使用Context
<br />
<div style={styleColor}>{getContext.text}</div>
</div >)
}
export default Grandson;